<template>
  <view ref="bodywk" @click="hanlder" :class="[customClass, 'overflow']" :style="[
    computedHeight ? { height: computedHeight } : '',
    computedWidth ? { width: computedWidth } : '',
    customCSSStyle,
  ]">
    <!-- #ifdef APP-NVUE -->
    <view v-if="isLoadEl" ref="nvueElAni" :animation="animationData"
      :class="['flex-col flex trani', animationName + reverseAniPrefxname, customClass]">
      <slot name="default"></slot>
    </view>
    <!-- #endif -->
    <!-- #ifndef APP-NVUE -->
    <view v-if="isLoadEl" ref="nvueElAni" :style="{
      transitionDuration: `${durationtos}ms`,
      transitionTimingFunction: 'ease',
    }" :class="['flex-col flex trani', animationClassName, customClass]">
      <slot name="default"></slot>
    </view>
    <!-- #endif -->
  </view>
</template>

<script lang="ts" setup>
/**
 * 动画
 * @description 提供了6组动画，并且每组件动画都支持反转播放，相当于12组动画了。可用于任何元素，进入场和出场的动画。
 */
import {
  getCurrentInstance,
  computed,
  ref,
  provide,
  inject,
  onMounted,
  onUnmounted,
  nextTick,
  watch,
} from "vue";
import { cssstyle, tmVuetify } from "../../tool/lib/interface";
import { custom_props, computedClass, computedStyle } from "../../tool/lib/minxs";
// #ifdef APP-PLUS-NVUE
const Binding = uni.requireNativePlugin("bindingx");
const dom = uni.requireNativePlugin("dom");
const animation = uni.requireNativePlugin("animation");
// #endif
// 混淆props共有参数
const props = defineProps({
  ...custom_props,
  duration: {
    type: Number,
    default: 300,
  },
  delay: {
    type: Number,
    default: 0,
  },
  //动画名称
  name: {
    type: String,
    default: "fade", //fade,left,right,up,down,zoom
  },
  autoPlay: {
    type: Boolean,
    default: true,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  height: {
    type: [Number, String],
    default: 0,
  },
  width: {
    type: [Number, String],
    default: 0,
  },
  //是否反向动画
  reverse: {
    type: [Boolean, String],
    default: false,
  },
  //每变动一次，就重置动画一下，这个属性不对外，特殊情况使用。
  initByWechat: {
    type: Boolean,
    default: false,
  },
});
const emits = defineEmits(["start", "end", "click"]);

function hanlder(e: any) {
  emits("click", e);
}
const proxy = getCurrentInstance()?.proxy ?? null;
//自定义样式：
const customCSSStyle = computed(() => computedStyle(props));
//自定类
const customClass = computed(() => computedClass(props));
//高度，
const computedHeight = computed(() => {
  if (!props.height || !Number(props.height)) {
    return 0;
  }
  if (
    String(props.height).indexOf("px") > -1 ||
    String(props.height).indexOf("rpx") > -1
  ) {
    return String(props.height);
  }
  return String(props.height) + "rpx";
});

// 宽度
const computedWidth = computed(() => {
  if (!props.width) {
    return 0;
  }
  if (String(props.width).indexOf("px") > -1 || String(props.width).indexOf("rpx") > -1) {
    return props.width;
  }
  return props.width + "rpx";
});
//动画名称
const animationName = computed(() => props.name || "fade");
//动画时长
const durationtos = ref(props.duration);
//是否反转。
const computedReverse = computed(() => props.reverse);
//反转动画前缀
const reverseAniPrefxname = computed(() => (computedReverse.value ? "-reverse" : ""));
//非nvue
const animationClassName = ref(animationName.value + reverseAniPrefxname.value);
//动画播放状态。0未开始,结束播放，1开始播放中,2结束。
const animationStatus = ref(0);
const tmid = ref<any>(Number(uni.$tm.u.getUid(3)));
//是否渲染完成。
const isLoadEl = ref(false);
//css3动画数据。
const animationData = ref(null);
watch([() => props.initByWechat, () => props.name], () => {
  reset();
});
watch([() => props.name], () => {
  animationClassName.value = animationName.value + reverseAniPrefxname.value;
});
function init() {
  nextTick(() => {
    isLoadEl.value = true;
    if (props.autoPlay == true && !props.disabled) {
      nextTick(() => play());
    }
  });
}

function play() {

  if (props.disabled == true) return;
  animationStatus.value = 0;
  // #ifdef APP-NVUE
  clearTimeout(tmid.value);
  nextTick(function () {
    tmid.value = setTimeout(function () {
      emits("start");
      nvueAmatons();
    }, 50);
  });
  // #endif
  // #ifndef APP-NVUE
  noNvueAmations();
  // #endif
}

function stop() {
  if (props.disabled == true) return;
  clearTimeout(tmid.value);
  animationStatus.value = 0;
}

function reset() {
  stop();
  animationStatus.value = 0;
}
//对外暴露方法。
defineExpose({
  init: init,
  play: play,
  stop: stop,
  reset: reset,
});
//获取当前播放状态。
function getPlayStatus() {
  return animationStatus.value;
}

onMounted(() => init());
onUnmounted(() => {
  clearTimeout(tmid.value);
  animationStatus.value = 0;
});
function nvueAmatonsReset() {
  var el = proxy?.$refs.nvueElAni;
  let propsAni = {};
  let rs = !computedReverse.value;
  return new Promise(su => {
    if (animationName.value == "fade") {
      propsAni = {
        opacity: rs ? 0 : 1,
        transformOrigin: "center center",
      };
    } else if (animationName.value == "up") {
      propsAni = {
        opacity: 1,
        transform: rs ? "translateY(0%)" : "translateY(-100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "down") {
      propsAni = {
        opacity: 1,
        transform: rs ? "translateY(0%)" : "translateY(100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "right") {
      propsAni = {
        opacity: 1,
        transform: rs ? "translateX(0%)" : "translateX(100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "left") {
      propsAni = {
        opacity: 1,
        transform: rs ? "translateX(0%)" : "translateX(-100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "zoom") {
      propsAni = {
        opacity: rs ? 0 : 1,
        transform: rs ? "scale(0.7,0.7)" : "scale(1,1)",
        transformOrigin: "center center",
      };
    }
    animation.transition(
      el,
      {
        styles: propsAni,
        duration: 1, //ms
        timingFunction: "ease",
        delay: 0, //ms
      },
      () => {
        su(true)
      }
    );
  })
}
function nvueAmatons() {
  var el = proxy?.$refs.nvueElAni;
  let propsAni = {};
  nvueAmatonsReset().then(() => {
    if (animationName.value == "fade") {
      propsAni = {
        opacity: computedReverse.value ? 0 : 1,
        transformOrigin: "center center",
      };
    } else if (animationName.value == "up") {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? "translateY(0%)" : "translateY(-100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "down") {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? "translateY(0%)" : "translateY(100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "right") {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? "translateX(0%)" : "translateX(100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "left") {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? "translateX(0%)" : "translateX(-100%)",
        transformOrigin: "center center",
      };
    } else if (animationName.value == "zoom") {
      propsAni = {
        opacity: computedReverse.value ? 0 : 1,
        transform: computedReverse.value ? "scale(0.7,0.7)" : "scale(1,1)",
        transformOrigin: "center center",
      };
    }
    emits("start");
    animationStatus.value = 1;
    clearTimeout(tmid.value);
    tmid.value = setTimeout(function () {
      animation.transition(
        el,
        {
          styles: propsAni,
          duration: props.duration, //ms
          timingFunction: "ease",
          delay: 0, //ms
        },
        () => {
          emits("end");
          animationStatus.value = 2;
        }
      );
    }, 20);
  })

}

function noNvueAmations() {
  clearTimeout(tmid.value);
  tmid.value = setTimeout(() => {
    if (computedReverse.value) {
      animationClassName.value = animationName.value;
    } else {
      animationClassName.value = animationName.value + "-reverse";
    }
    tmid.value = setTimeout(() => {
      emits("end");
    }, props.duration);

  }, 20);

}
</script>

<style scoped>
.fade {
  opacity: 0;
}

.fade-reverse {
  opacity: 1;
}

.up {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  top: 0vh;
  /* #endif */
}

.up-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(-101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  top: -100vh;
  /* #endif */
}

.down {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  top: 0vh;
  /* #endif */

}

.down-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  top: 100vh;
  /* #endif */
}

.left {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: 0%;
  /* #endif */
}

.left-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(-101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: -101%;
  /* #endif */
}

.right {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: 0%;
  /* #endif */
}

.right-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: 101%;
  /* #endif */
}

.zoom {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: scale(0.7, 0.7);
  /* #endif */
  opacity: 0;
}

.zoom-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: scale(1, 1);
  /* #endif */
  opacity: 1;

}
</style>
